Add a focus-within state
authorMatthias Clasen <mclasen@redhat.com>
Thu, 16 Apr 2020 05:36:13 +0000 (01:36 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 16 Apr 2020 16:31:01 +0000 (12:31 -0400)
This is used for widgets that contain the focus widget,
reserving the focused state for the focus location itself.

This aligns our focus state handling with
https://www.w3.org/TR/selectors-4/

gtk/gtkcssselector.c
gtk/gtkcsstypes.c
gtk/gtkenums.h
gtk/gtkwidgetprivate.h
gtk/gtkwindow.c

index 57520054630c5f7e7a56c1126417e44a1d284299..c7bc7bd7d52354e16dfaecbd6223263b52ca2c5c 100644 (file)
@@ -1283,6 +1283,7 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser   *parser,
         { "visited",        GTK_STATE_FLAG_VISITED, },
         { "checked",        GTK_STATE_FLAG_CHECKED, },
         { "focus-visible",  GTK_STATE_FLAG_FOCUS_VISIBLE, },
+        { "focus-within",   GTK_STATE_FLAG_FOCUS_WITHIN, },
       };
       guint i;
 
index 928b0f9a2a35190637105afb5c6e3a960fb9d7d6..ea83226317f148a3b0c89414cd514252f78cbccf 100644 (file)
@@ -232,7 +232,8 @@ gtk_css_pseudoclass_name (GtkStateFlags state)
     "visited",
     "checked",
     "drop(active)",
-    "focus-visible"
+    "focus-visible",
+    "focus-within"
   };
   guint i;
 
index 658be5f338b2823b53114534b99130cee4df1a62..a7657a84edc64b60b53fcc07400b8ae750716a64 100644 (file)
@@ -736,6 +736,7 @@ typedef enum
  * @GTK_STATE_FLAG_CHECKED: Widget is checked
  * @GTK_STATE_FLAG_DROP_ACTIVE: Widget is highlighted as a drop target for DND
  * @GTK_STATE_FLAG_FOCUS_VISIBLE: Widget has the visible focus
+ * @GTK_STATE_FLAG_FOCUS_WITHIN: Widget contains the keyboard focus
  *
  * Describes a widget state. Widget states are used to match the widget
  * against CSS pseudo-classes. Note that GTK extends the regular CSS
@@ -757,7 +758,8 @@ typedef enum
   GTK_STATE_FLAG_VISITED       = 1 << 10,
   GTK_STATE_FLAG_CHECKED       = 1 << 11,
   GTK_STATE_FLAG_DROP_ACTIVE   = 1 << 12,
-  GTK_STATE_FLAG_FOCUS_VISIBLE = 1 << 13
+  GTK_STATE_FLAG_FOCUS_VISIBLE = 1 << 13,
+  GTK_STATE_FLAG_FOCUS_WITHIN  = 1 << 14
 } GtkStateFlags;
 
 /**
index b2a4836ca0cadd5f1f936716cdacb1eed4a32a52..1b104e77d98d930232c9e7f337c9ffb45754273a 100644 (file)
@@ -45,7 +45,7 @@ typedef gboolean (*GtkSurfaceTransformChangedCallback) (GtkWidget
                                                         const graphene_matrix_t *surface_transform,
                                                         gpointer                 user_data);
 
-#define GTK_STATE_FLAGS_BITS 14
+#define GTK_STATE_FLAGS_BITS 15
 
 typedef struct _GtkWidgetSurfaceTransformData
 {
index 0451719907c5786f13347f5beb1072307bdc0393..3bd8d30e9f05a4b05437cefb8fd3a28507cdbfac 100644 (file)
@@ -5568,7 +5568,7 @@ synthesize_focus_change_events (GtkWindow *window,
   else
     ancestor = NULL;
 
-  flags = GTK_STATE_FLAG_FOCUSED;
+  flags = GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_FOCUS_WITHIN;
   if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
     flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
 
@@ -5612,8 +5612,14 @@ synthesize_focus_change_events (GtkWindow *window,
       gtk_widget_set_focus_child (widget, NULL);
       prev = widget;
       widget = gtk_widget_get_parent (widget);
+
+      flags = flags & ~GTK_STATE_FLAG_FOCUSED;
     }
 
+  flags = GTK_STATE_FLAG_FOCUS_WITHIN;
+  if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
+    flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
+
   list = NULL;
   for (widget = new_focus; widget; widget = gtk_widget_get_parent (widget))
     list = g_list_prepend (list, widget);
@@ -5652,6 +5658,10 @@ synthesize_focus_change_events (GtkWindow *window,
         }
       check_crossing_invariants (widget, &crossing);
       gtk_widget_handle_crossing (widget, &crossing, 0, 0);
+
+      if (l->next == NULL)
+        flags = flags | GTK_STATE_FLAG_FOCUSED;
+
       gtk_widget_set_state_flags (widget, flags, FALSE);
       gtk_widget_set_focus_child (widget, focus_child);
     }